package com.sig.util;

import org.apache.commons.lang3.ArrayUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;

/**
 * 压缩和解压缩工具
 *
 * @author sig
 * @since 2019/1/26
 */
public final class CompressionUtil {
    private static final int BUFF_SIZE = 1024;

    private CompressionUtil() {
    }

    public static byte[] unZlib(final byte[] input) {
        if (ArrayUtils.isEmpty(input))
            return input;
        Inflater inflater = new Inflater();
        byte[] output = null;
        inflater.reset();
        inflater.setInput(input);
        final ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
        try {
            final byte[] buf = new byte[BUFF_SIZE];
            int len;
            while (!inflater.finished()) {
                len = inflater.inflate(buf);
                bos.write(buf, 0, len);
            }
            output = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            inflater.end();
        }
        return output;
    }

    public static byte[] zlib(final byte[] input) {
        if (ArrayUtils.isEmpty(input))
            return input;
        Deflater deflater = new Deflater();
        deflater.reset();
        deflater.setLevel(Deflater.BEST_COMPRESSION);
        deflater.setInput(input);
        deflater.finish();
        byte[] output;
        final ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
        try {
            byte[] buf = new byte[zlibBound(input.length)];
            int len;
            while (!deflater.finished()) {
                len = deflater.deflate(buf);
                bos.write(buf, 0, len);
            }
            output = bos.toByteArray();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            deflater.end();
        }
        return output;
    }

    public static int zlibBound(final int sourceLen) {
        return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13;
    }

    public static byte[] gzip(final byte[] input) {
        if (ArrayUtils.isEmpty(input))
            return input;
        byte[] output = new byte[0];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        GZIPOutputStream gos;
        try {
            gos = new GZIPOutputStream(bos);
            gos.write(input);
            gos.finish();
            gos.flush();
            gos.close();
            gos.flush();
            output = bos.toByteArray();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return output;
    }

    public static byte[] unGzip(final byte[] input) {
        if (ArrayUtils.isEmpty(input))
            return input;
        byte[] output = new byte[0];
        ByteArrayInputStream bis = new ByteArrayInputStream(input);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        GZIPInputStream gis;
        try {
            gis = new GZIPInputStream(bis);
            byte[] buf = new byte[BUFF_SIZE];
            int len;
            while ((len = gis.read(buf, 0, buf.length)) != -1)
                bos.write(buf, 0, len);
            bos.flush();
            output = bos.toByteArray();
            bos.close();
            gis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return output;
    }
}
